package com.ld.oauth2.config.oauth;

import com.ld.oauth2.service.CustomUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import javax.sql.DataSource;

@Configuration
@EnableAuthorizationServer // 开启了认证服务器
@Order(6)
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired//刷新令牌时需要使用
    private CustomUserDetailsService customUserDetailService;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;


    @Bean//授权码管理策略
    public AuthorizationCodeServices jdbcAuthorizationCodeServices(){
        return new JdbcAuthorizationCodeServices(dataSource);
    }

    @Bean
    public ClientDetailsService jdbcClientDetailsService(){
        return  new JdbcClientDetailsService(dataSource);
    }

    /**
     * 配置允许访问此认证服务器的客户端信息
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //内存管理方式
//        clients.inMemory().withClient("ld-pc")//客户端id
//                .secret(passwordEncoder.encode("ld-secret"))//客户端密码
//        .resourceIds("product-server")//资源id针对的是微服务 多个用逗号隔开
//        .authorizedGrantTypes("authorization_code","password","implicit","client_credentials","refresh_token")//五种模式
//                .scopes("all")//授权标识 只是取的名字 并不代表所有都可以访问
//        .autoApprove(false)//false会跳转到一个授权页面 进行手动授权
//        .redirectUris("http://www.baidu.com");//客户端的回调地址 若有多个客户端 则在下面用and()再继续配置
//
        //jdbc管理方式
        clients.withClientDetails(jdbcClientDetailsService());
    }

    /**
     * 密码模式需要配置这个
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
        endpoints.userDetailsService(customUserDetailService);
        endpoints.tokenServices(authorizationServerTokenServices());
        //jwt模式还要记得指定jwt转换器
        endpoints.tokenStore(tokenSTore()).accessTokenConverter(jwtAccessTokenConverter);
        //授权码策略 会把产生的授权码防到auth_code表中  若使用了以后就会删除掉
        endpoints.authorizationCodeServices(jdbcAuthorizationCodeServices());
    }

    /**
     *  涉及到接口的访问权限，需要在这进行必要的设置
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        //开启/oauth/check_token的访问权限（限制）
        security.checkTokenAccess("isAuthenticated()");
        //开启/oauth/token_key的访问权限（允许）
        security.tokenKeyAccess("permitAll()");
        //允许客户端表单验证
        security.allowFormAuthenticationForClients();
    }

    /**
     * 令牌以什么形式存储
     * @return
     */
    @Bean
    public TokenStore tokenSTore() {
        //通过redis管理令牌
        //return new RedisTokenStore(redisConnectionFactory);
        //return new JdbcTokenStore(dataSource());
        //jwt方式管理令牌
        return new JwtTokenStore(jwtAccessTokenConverter);
    }




    /**
     * 令牌的刷新时间等设置
     * @return
     */
    public AuthorizationServerTokenServices authorizationServerTokenServices(){
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setSupportRefreshToken(true);//是否开启令牌刷新
        defaultTokenServices.setTokenStore(tokenSTore());
        //针对令牌的添加
        defaultTokenServices.setTokenEnhancer(jwtAccessTokenConverter);
        //令牌有效时间 一般设置为两个小时
        defaultTokenServices.setAccessTokenValiditySeconds(60 * 60 * 24 * 30);
        //刷新令牌的有效时间
        defaultTokenServices.setRefreshTokenValiditySeconds(60 * 60 * 24 * 90);
        return defaultTokenServices;
    }


}
